import { message } from "antd";
import axios, {
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from "axios";
import store from "store";

const { CancelToken } = axios;
const cancelRequest = new Map();

// 扩展 Axios 配置类型（可选）
export interface CustomAxiosConfig extends AxiosRequestConfig {
  token?: string; // 自定义扩展字段
}

export interface CustomInternalAxiosRequestConfig
  extends InternalAxiosRequestConfig {
  token?: string; // 自定义扩展字段
}

class AxiosSingleton {
  private static instance: AxiosInstance | null = null;
  private static isInitialized: boolean = false;

  // 私有构造函数防止外部实例化
  private constructor() {}

  public static getInstance(customConfig?: CustomAxiosConfig): AxiosInstance {
    console.log(AxiosSingleton.instance, "AxiosSingleton.instance");
    if (!AxiosSingleton.instance || !AxiosSingleton.isInitialized) {
      // 合并默认配置和自定义配置
      const defaultConfig: CustomAxiosConfig = {
        baseURL: process.env.baseURL || "",
        timeout: 15000,
        headers: {
          "Content-Type": "application/json",
          "X-Requested-With": "XMLHttpRequest",
        },
        // 合并自定义配置（如果有）
        ...(customConfig || {}),
      };

      // 创建 axios 实例
      AxiosSingleton.instance = axios.create(defaultConfig);

      // 初始化请求拦截器
      this.setupRequestInterceptor();

      // 初始化响应拦截器
      this.setupResponseInterceptor();

      AxiosSingleton.isInitialized = true;
    }

    return AxiosSingleton.instance;
  }

  // 私有化克隆方法防止通过 new 创建实例
  private static cloneInstance(): never {
    throw new Error("Use getInstance() method to get the singleton instance");
  }

  private static setupRequestInterceptor(): void {
    AxiosSingleton.instance!.interceptors.request.use(
      (config: CustomInternalAxiosRequestConfig) => {
        // 从 localStorage 获取 token
        // const token = localStorage.getItem("auth_token");
        const user = store.get("user") || {};
        if (user?.token) {
          config.headers.Authorization = `Bearer ${user?.token}`;
        }

        // 如果配置中携带了 token，优先使用
        if (config?.token) {
          config.headers.Authorization = `Bearer ${config.token}`;
        }

        return config;
      },
      (error: any) => Promise.reject(error)
    );
  }

  private static setupResponseInterceptor(): void {
    AxiosSingleton.instance!.interceptors.response.use(
      (response: AxiosResponse) => {
        // 直接返回响应数据（根据后端约定）
        return response.data;
      },
      (error: any) => {
        // 统一错误处理
        this.handleError(error);
        return Promise.reject(error);
      }
    );
  }

  private static handleError(error: any): void {
    if (error.response) {
      // 服务器有响应（4xx/5xx）
      const { status } = error.response;

      switch (status) {
        case 401:
          console.error("Unauthorized, redirecting to login...");
          window.location.href = "/login";
          break;
        case 403:
          console.error("Forbidden");
          break;
        case 404:
          console.error("Resource not found");
          break;
        default:
          console.error(`Request error [${status}]:`, error.response.data);
      }
    } else if (error.code === "ECONNABORTED") {
      console.error("Request timeout");
    } else {
      console.error("Network error:", error.message);
    }
  }
}

// 导出单例访问方法
export const axiosInstance = AxiosSingleton.getInstance();

// 类型安全的请求方法示例
export async function get<T = any>(
  url: string,
  config?: CustomAxiosConfig
): Promise<T> {
  return axiosInstance.get(url, config);
}

export async function post<T = any>(
  url: string,
  data?: any,
  config?: CustomAxiosConfig
): Promise<T> {
  return axiosInstance.post(url, data, config);
}

export const api = async (config: AxiosRequestConfig) => {
  const requestConfig: AxiosRequestConfig = {
    ...config,
    cancelToken: config.cancelToken
      ? config.cancelToken
      : new CancelToken((cancel) => {
          cancelRequest.set(Symbol(Date.now()), {
            pathname: window.location.pathname,
            cancel,
          });
        }),
  };
  try {
    const response: Response<any> = await axiosInstance(requestConfig);

    if (response.code !== 200) {
      message.error(response.message);
      return undefined;
    }
    return response;
  } catch (error: any) {
    const { response = {}, statusText } = error;
    message.error(response.data?.message || statusText);
  }
};
export type Response<T> = {
  code: number;
  message: string;
  t?: T;
};
